package base.thread_demo.demo20;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 从这个demo20开始就没看了
 */
public class TestAccountDemo1 {


    public static void main(String[] args) {
        Account account = new AccountSafe(10000);//初始账户存入1万块钱
        Account.demo(account);

        Account account2 = new AccountCas(10000);
        Account.demo(account2);
    }

}

class AccountCas implements Account {
    private AtomicInteger balance;

    public AccountCas(int balance) {
        this.balance = new AtomicInteger(balance);
    }

    @Override
    public Integer getBalance() {
        return balance.get();
    }

    @Override
    public void withdraw(Integer amount) {
		/*
		while(true) {
			// 获取余额的最新值
			int prev = balance.get();
			// 修改后的余额
			int next = prev - amount;
			// 真正修改
			if(balance.compareAndSet(prev, next)) {// 如果balance对象的value的最新值和prev比较相等(说明别的线程还没有修改)，则用next设置为balance对象的value值，退出循环尝试修改操作
				break;
			}
		}
		*/
        // 或者
        balance.getAndAdd(-amount);//AtomicXXX的API底层都是原子操作，无须我们关注
    }

}

/*
 *
 */
class AccountSafe implements Account{

    private Integer balance;

    public AccountSafe(Integer balance) {
        this.balance = balance;
    }

    @Override
    public Integer getBalance() {
        return this.balance;
    }

    @Override
    public void withdraw(Integer amount) {
        synchronized (this) {//添加synchronized解决线程安全问题
            this.balance -= amount;
        }
    }

}

interface Account {
    // 获取余额
    Integer getBalance();

    // 取款
    void withdraw(Integer amount);

    /**
     * 方法内会启动 1000 个线程，每个线程做 -10 元 的操作
     * 如果初始余额为 10000 那么正确的结果应当是 0
     */
    static void demo(Account account) {
        List<Thread> ts = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(()->{
                account.withdraw(10);
            }));
        }
        long start = System.nanoTime();
        ts.forEach(Thread::start);//启动1000个线程
        ts.forEach(t -> {
            try {
                t.join();//等待1000个线程执行完毕
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.nanoTime();
//        System.out.println("start:"+start+", end:"+end);
        System.out.println(account.getBalance()+ " cost:"+ (end-start)/1000000 + " ms");
    }
}
